package poker

import (
	"errors"
	"math/rand"
	"time"
)

type Decks struct {
	hasJoker  bool    `remark:"是否包含鬼牌"`
	cards     []*Card `remark:"未发的牌"`
	drawCards []*Card `remark:"已发的牌"`
	maxValue  int     `value:"1~15,remark:"整副牌最大的牌值"`
}

func NewDecks(hasJoker bool, maxValue int) *Decks {
	decks := &Decks{hasJoker: hasJoker, maxValue: maxValue}
	return decks.init()
}

func (this *Decks) Cards() []*Card {
	return this.cards
}

func (this *Decks) DrawCards() []*Card {
	return this.drawCards
}
func (this *Decks) MaxValue() int {
	return this.maxValue
}

func (this *Decks) HasJoker() bool {
	return this.hasJoker
}

func (this *Decks) init() *Decks {
	maxVal := this.maxValue
	for i := 1; i <= 4; i++ {
		for v := 1; v <= 13; v++ {
			this.cards = append(this.cards, NewCard(i, v, maxVal))
		}
	}
	if this.hasJoker {
		this.cards = append(this.cards,
			NewCard(SUIT_JOKER, 14, maxVal),
			NewCard(SUIT_JOKER, 15, maxVal),
		)
	}
	return this
}

func (this *Decks) Shuffle() *Decks {
	rand.Seed(time.Now().UnixNano())
	c := make([]*Card, len(this.cards))
	copy(c, this.cards)
	rand.Shuffle(len(this.cards), func(i, j int) {
		c[i], c[j] = c[j], c[i]
	})
	this.cards = c
	return this
}

func (this *Decks) Draw() (*Card, error) {
	l := len(this.cards)
	if l == 0 {
		return nil, errors.New("牌已发完")
	}
	card := this.cards[l-1:][0]
	this.cards = this.cards[:l-1]
	this.drawCards = append(this.drawCards, card)
	return card, nil
}

func (this *Decks) DrawHandCards(counts int) (*HandCard, error) {
	handCards := NewHandCard(make([]*Card, 0))
	for i := 0; i < counts; i++ {
		card, err := this.Draw()
		if err != nil {
			return handCards, err
		}
		handCards.Push(card)
	}
	return handCards, nil
}

func (this *Decks) Rollback(isUnshift bool) *Decks {
	l := len(this.drawCards)
	if l == 0 {
		return this
	}
	card := this.drawCards[l-1:][0]
	this.drawCards = this.drawCards[:l-1]
	if isUnshift {
		cards := make([]*Card, 1)
		cards[0] = card
		this.cards = append(cards, this.drawCards...)
	} else {
		this.cards = append(this.drawCards, card)
	}
	return this
}
func (this *Decks) InitCards(cards []*Card, drawCards []*Card) *Decks {
	this.cards = cards
	this.drawCards = drawCards
	return this
}
